/*
 * File Name  :CommonService.java
 * Create Date:2012-11-3 下午5:54:12
 * Author     :woden
 */

package com.wodensoft.core.db;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.wodensoft.core.BeanFactory;
import com.wodensoft.core.exception.ExceptionType;
import com.wodensoft.core.exception.SystemRuntimeException;

/**
 * 通用数据库服务.<br>
 * 封装通用hibernate操作。
 * 
 */
public class ORMService {

    /**
     * 获取通用数据库服务.<br>
     * 单例模式.
     * 
     * @return 通用数据库服务对象 <code>CommonService</code>.
     */
    public static ORMService getInstance() {
        ORMService service = BeanFactory.getInstance().getSingleBean(ORMService.class);
        return service;
    }

    /**
     * <code>SessionFactory</code>对象.
     */
    private SessionFactory sessionFactory;

    /**
     * 执行自定义HQL操作.
     * 
     * @param hql
     * @param values
     * @throws SystemRuntimeException
     */
    public void executeHQL(String hql, Object... values) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            Query query = session.createQuery(hql);
            if (values != null) {
                for (int i = 0; i < values.length; i++) {
                    query.setParameter(i, values[i]);
                }
            }
            query.executeUpdate();
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "执行[" + hql + "]出错.", e);
        }
    }

    /**
     * 根据查询条件查找唯一记录.
     * 
     * @param entryName
     * @param queryMap
     * @return
     * @throws SystemRuntimeException
     */
    @SuppressWarnings("rawtypes")
    public Object find(String entryName, Map queryMap) {
        String hql = "from " + entryName + " " + QueryHQLBuilder.build(queryMap);
        Session session = this.sessionFactory.getCurrentSession();
        try {
            Query query = session.createQuery(hql);
            return query.uniqueResult();
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "查询[" + hql + "]出错.", e);
        }
    }

    /**
     * 自定义查找.
     * 
     * @param entryName
     *            对象名.
     * @param keyName
     *            字段Key.
     * @param keyValue
     *            字段值.
     * @return 满足条件的唯一对象.
     */
    @SuppressWarnings({ "rawtypes" })
    public Object findByKey(String entryName, String keyName, Object keyValue) {
        Session session = this.sessionFactory.getCurrentSession();
        Query query = session.createQuery("from " + entryName + " where " + keyName + " = ?");
        query.setParameter(0, keyValue);
        List result = query.list();
        if (result != null && result.size() > 0) {
            return result.get(0);
        } else {
            return null;
        }
    }

    /**
     * 查找.
     * 
     * @param entryName
     *            对象名.
     * @param pk
     *            主键.
     * @return 返回实例.
     */
    public Object findByPk(String entryName, Serializable pk) {
        Session session = this.sessionFactory.getCurrentSession();
        Object entry = session.get(entryName, pk);
        if (entry == null) {
            return null;
        } else {
            return entry;
        }
    }

    /**
     * 自定义HQL查询.
     * 
     * @param hql
     *            HQL语句.
     * @param values
     *            入参数组.
     * @return 结果对象.
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    public Object findHQL(String hql, Object... values) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            Query query = session.createQuery(hql);
            if (values != null) {
                for (int i = 0; i < values.length; i++) {
                    query.setParameter(i, values[i]);
                }
            }
            return query.uniqueResult();
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "查询[" + hql + "]出错.", e);
        }
    }

    /**
     * 自定义SQL查询.
     * 
     * @param sql
     *            sql语句.
     * @param values
     *            替换入参.
     * @return 结果对象.
     * @throws SystemRuntimeException
     */
    public Object findSQL(String sql, Object... values) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            SQLQuery query = session.createSQLQuery(sql);
            if (values != null) {
                for (int i = 0; i < values.length; i++) {
                    query.setParameter(i, values[i]);
                }
            }
            return query.uniqueResult();
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "查询[" + sql + "]出错.", e);
        }
    }

    /**
     * 获取表记录总数.
     * 
     * @param entryName
     *            对象名.
     * @return 当前表记录总数.
     * @throws SystemRuntimeException
     */
    public Long getCount(String entryName) {
        Session session = this.sessionFactory.getCurrentSession();
        Long count = null;
        try {
            count = (Long) session.createQuery("select count(*) from " + entryName).list().iterator().next();
            return count;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "查询[" + entryName + "]总数出错.", e);
        }

    }

    /**
     * 获取表记录总数.
     * 
     * @param entryName
     *            对象名.
     * @param queryMap
     *            动态查询条件.
     * @return 符合条件的记录总数.
     * @throws SystemRuntimeException
     */
    @SuppressWarnings("rawtypes")
    public Long getCount(String entryName, Map queryMap) {
        Session session = this.sessionFactory.getCurrentSession();
        Long count = null;
        try {
            String hql = "select count(*) from " + entryName + " " + QueryHQLBuilder.buildWhere(queryMap);
            count = (Long) session.createQuery(hql).list().iterator().next();
            return count;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "查询[" + entryName + "]总数出错.", e);
        }

    }

    /**
     * 从PO对象中获取对象名.
     * 
     * @param po
     *            动态对象.
     * @return 对象名.
     */
    @SuppressWarnings({ "rawtypes" })
    protected String getEntryName(Map po) {
        if (po != null && po.containsKey("$type$")) {
            return (String) po.get("$type$");
        }

        throw new SystemRuntimeException(ExceptionType.DB, "对象无指定实体.");
    }

    /**
     * 自定义HQL查询.
     * 
     * @param queryMap
     *            动态查询入参,参考:{@link BaseService.QueryHQLBuilder}.
     * @return 结果数组.
     * @throws SystemRuntimeException
     *             查询出错时抛出.
     */
    @SuppressWarnings("rawtypes")
    public List query(String entryName, Map queryMap) {
        String hql = "from " + entryName + " " + QueryHQLBuilder.build(queryMap);
        return this.queryHQL(hql);
    }

    /**
     * 查找所有
     * 
     * @param entryName
     *            对象名.
     * @return 单表所有记录.
     */
    @SuppressWarnings({ "rawtypes" })
    public List queryAll(String entryName) {
        Session session = this.sessionFactory.getCurrentSession();
        return session.createQuery("from " + entryName).list();
    }

    /**
     * 自定义HQL查询.
     * 
     * @param hql
     *            HQL语句.
     * @param values
     *            入参数组.
     * @return 结果列表.
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    @SuppressWarnings({ "rawtypes" })
    public List queryHQL(String hql, Object... values) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            Query query = session.createQuery(hql);
            if (values != null) {
                for (int i = 0; i < values.length; i++) {
                    query.setParameter(i, values[i]);
                }
            }
            return query.list();
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "查询[" + hql + "]出错.", e);
        }
    }

    /**
     * 自定义HQL分页查询.
     * 
     * @param hql
     *            HQL语句.
     * @param firstResult
     *            记录开端.
     * @param maxResult
     *            最大记录数.
     * @param values
     *            入参数组.
     * @return 结果列表.
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    @SuppressWarnings({ "rawtypes" })
    public List queryHQLPage(String hql, int firstResult, int maxResult, Object... values) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            Query query = session.createQuery(hql);
            if (values != null) {
                for (int i = 0; i < values.length; i++) {
                    query.setParameter(i, values[i]);
                }
            }
            return query.setFirstResult(firstResult).setMaxResults(maxResult).list();
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "执行[" + hql + "]出错.", e);
        }
    }

    /**
     * 
     * @param entryName
     * @param firstResult
     *            记录开端.
     * @param maxResult
     *            最大记录数.
     * @param queryMap
     *            动态查询入参,参考:{@link BaseService.QueryHQLBuilder}.
     * @return 结果数组.
     * @throws SystemRuntimeException
     *             查询出错时抛出.
     */
    @SuppressWarnings({ "rawtypes" })
    public List queryPage(String entryName, int firstResult, int maxResult, Map queryMap) {
        String hql = "from " + entryName + " " + QueryHQLBuilder.build(queryMap);
        return this.queryHQLPage(hql, firstResult, maxResult);
    }

    /**
     * 自定义SQL查询.
     * 
     * @param sql
     *            sql语句.
     * @param values
     *            替换入参.
     * @return 查询返回列表.
     * @throws SystemRuntimeException
     */
    @SuppressWarnings("rawtypes")
    public List querySQL(String sql, Object... values) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            SQLQuery query = session.createSQLQuery(sql);
            if (values != null) {
                for (int i = 0; i < values.length; i++) {
                    query.setParameter(i, values[i]);
                }
            }
            return query.list();
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "查询[" + sql + "]出错.", e);
        }
    }

    /**
     * 删除.
     * 
     * @param po
     *            动态PO实例
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    public void remove(Map<String, Object> po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.delete(this.getEntryName(po), po);
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "删除出错.", e);
        }
    }

    /**
     * 删除。
     * 
     * @param po 静态实例
     */
    public void removePO(Object po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.delete(po);
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "删除出错.", e);
        }
    }

    /**
     * 新增.
     * 
     * @param po
     *            动态PO实例
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    public void save(Map<String, Object> po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.save(this.getEntryName(po), po);
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "新增出错.", e);
        }
    }

    /**
     * 新增。
     * 
     * @param po 静态实例
     */
    public void savePO(Object po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.save(po);
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "新增出错.", e);
        }
    }

    /**
     * 批量新增.
     * 
     * @param list
     *            动态PO实例列表.
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    public void saveBatch(List<Map<String, Object>> list) {
        if (list == null || list.size() == 0) {
            return;
        }
        Session session = this.sessionFactory.getCurrentSession();
        try {
            for (Map<String, Object> po : list) {
                session.save(this.getEntryName(po), po);
            }
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "新增出错.", e);
        }
    }

    /**
     * 批量新增。
     * 
     * @param list 静态实例列表。
     */
    public void saveBatchPO(List<Object> list) {
        if (list == null || list.size() == 0) {
            return;
        }
        Session session = this.sessionFactory.getCurrentSession();
        try {
            for (Object po : list) {
                session.save(po);
            }
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "新增出错.", e);
        }
    }

    /**
     * 新增或更新.
     * 
     * @param po
     *            动态PO实例
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    public void saveOrUpdate(Map<String, Object> po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.saveOrUpdate(this.getEntryName(po), po);
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "新增或更新出错.", e);
        }
    }

    /**
     * 新增或更新.
     * 
     * @param po
     *            静态实例
     */
    public void saveOrUpdatePO(Object po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.saveOrUpdate(po);
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "新增或更新出错.", e);
        }
    }

    /**
     * Spring容器使用.
     * 
     * @param sessionFactory
     */
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /**
     * 更新.
     * 
     * @param po
     *            动态PO实例
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    public void update(Map<String, Object> po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.update(this.getEntryName(po), po);
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "更新出错.", e);
        }
    }

    /**
     * 更新。
     * 
     * @param po 静态实例。
     */
    public void updatePO(Object po) {
        Session session = this.sessionFactory.getCurrentSession();
        try {
            session.update(po);
        } catch (SystemRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SystemRuntimeException(ExceptionType.DB, "更新出错.", e);
        }
    }

    /**
     * 分页查询.
     * 
     * @param entryName
     *            对象名.
     * @param start
     *            起点.
     * @param limit
     *            限制.
     * @return 对象集.
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    public DataPackage queryPackage(String entryName, int start, int limit) {
        DataPackage result = new DataPackage();
        result.setStart(start);
        result.setLimit(limit);
        result.setTotalRecord(getCount(entryName));
        result.setList(queryHQLPage("from " + entryName, result.getStart(), result.getLimit()));
        return result;
    }

    /**
     * 分页查询.
     * 
     * @param entryName
     *            对象名.
     * @param start
     *            起点.
     * @param limit
     *            限制.
     * @param queryMap
     *            动态查询入参,参考:{@link BaseService.QueryHQLBuilder}.
     * @return 对象集.
     * @throws SystemRuntimeException
     *             数据操作失败时抛出.
     */
    @SuppressWarnings("rawtypes")
    public DataPackage queryPackage(String entryName, int start, int limit, Map queryMap) {
        DataPackage result = new DataPackage();
        result.setStart(start);
        result.setLimit(limit);
        result.setTotalRecord(getCount(entryName, queryMap));
        result.setList(queryPage(entryName, result.getStart(), result.getLimit(), queryMap));
        return result;
    }
}
